<template>
  <div class="content">
    <div class="app-stencil" ref="stencilContainer"></div>
    <div class="app-content" ref="containerRef"></div>
  </div>
</template>

<script>
import { Graph, ObjectExt } from "@antv/x6";
import UmlJson from "../data/uml.json";

export default {
  name: "uml",
  mounted() {
    this.init();
  },
  methods: {
    init() {
      // #region 注册基础图形
      Graph.registerNode(
        "class",
        {
          inherit: "rect",
          markup: [
            {
              tagName: "rect",
              selector: "body",
            },
            {
              tagName: "rect",
              selector: "name-rect",
            },
            {
              tagName: "rect",
              selector: "attrs-rect",
            },
            {
              tagName: "rect",
              selector: "methods-rect",
            },
            {
              tagName: "text",
              selector: "name-text",
            },
            {
              tagName: "text",
              selector: "attrs-text",
            },
            {
              tagName: "text",
              selector: "methods-text",
            },
          ],
          attrs: {
            rect: {
              width: 160,
            },
            body: {
              stroke: "#fff",
            },
            "name-rect": {
              fill: "#5f95ff",
              stroke: "#fff",
              strokeWidth: 0.5,
            },
            "attrs-rect": {
              fill: "#eff4ff",
              stroke: "#fff",
              strokeWidth: 0.5,
            },
            "methods-rect": {
              fill: "#eff4ff",
              stroke: "#fff",
              strokeWidth: 0.5,
            },
            "name-text": {
              ref: "name-rect",
              refY: 0.5,
              refX: 0.5,
              textAnchor: "middle",
              fontWeight: "bold",
              fill: "#fff",
              fontSize: 12,
            },
            "attrs-text": {
              ref: "attrs-rect",
              refY: 0.5,
              refX: 5,
              textAnchor: "left",
              fill: "black",
              fontSize: 10,
            },
            "methods-text": {
              ref: "methods-rect",
              refY: 0.5,
              refX: 5,
              textAnchor: "left",
              fill: "black",
              fontSize: 10,
            },
          },
          propHooks(meta) {
            const { name, attributes, methods, ...others } = meta;

            if (!(name && attributes && methods)) {
              return meta;
            }

            const rects = [
              { type: "name", text: name },
              { type: "attrs", text: attributes },
              { type: "methods", text: methods },
            ];

            let offsetY = 0;
            rects.forEach((rect) => {
              const height = rect.text.length * 12 + 16;
              ObjectExt.setByPath(
                others,
                `attrs/${rect.type}-text/text`,
                rect.text.join("\n")
              );
              ObjectExt.setByPath(
                others,
                `attrs/${rect.type}-rect/height`,
                height
              );
              ObjectExt.setByPath(
                others,
                `attrs/${rect.type}-rect/transform`,
                "translate(0," + offsetY + ")"
              );
              offsetY += height;
            });

            others.size = { width: 160, height: offsetY };

            return others;
          },
        },
        true
      );

      // 继承
      Graph.registerEdge(
        "extends",
        {
          inherit: "edge",
          attrs: {
            line: {
              strokeWidth: 1,
              targetMarker: {
                name: "path",
                d: "M 20 0 L 0 10 L 20 20 z",
                fill: "white",
                offsetX: -10,
              },
            },
          },
        },
        true
      );

      // 实现
      Graph.registerEdge(
        "implement",
        {
          inherit: "edge",
          attrs: {
            line: {
              strokeWidth: 1,
              strokeDasharray: "3,3",
              targetMarker: {
                name: "path",
                d: "M 20 0 L 0 10 L 20 20 z",
                fill: "white",
                offsetX: -10,
              },
            },
          },
        },
        true
      );

      // 组合
      Graph.registerEdge(
        "composition",
        {
          inherit: "edge",
          attrs: {
            line: {
              strokeWidth: 1,
              sourceMarker: {
                name: "path",
                d: "M 30 10 L 20 16 L 10 10 L 20 4 z",
                fill: "black",
                offsetX: -10,
              },
              targetMarker: {
                name: "path",
                d: "M 6 10 L 18 4 C 14.3333 6 10.6667 8 7 10 L 18 16 z",
                fill: "black",
                offsetX: -5,
              },
            },
          },
        },
        true
      );

      // 聚合
      Graph.registerEdge(
        "aggregation",
        {
          inherit: "edge",
          attrs: {
            line: {
              strokeWidth: 1,
              sourceMarker: {
                name: "path",
                d: "M 30 10 L 20 16 L 10 10 L 20 4 z",
                fill: "white",
                offsetX: -10,
              },
              targetMarker: {
                name: "path",
                d: "M 6 10 L 18 4 C 14.3333 6 10.6667 8 7 10 L 18 16 z",
                fill: "black",
                offsetX: -5,
              },
            },
          },
        },
        true
      );

      // 关联
      Graph.registerEdge(
        "association",
        {
          inherit: "edge",
          attrs: {
            line: {
              strokeWidth: 1,
              targetMarker: {
                name: "path",
                d: "M 6 10 L 18 4 C 14.3333 6 10.6667 8 7 10 L 18 16 z",
                fill: "black",
                offsetX: -5,
              },
            },
          },
        },
        true
      );
      // #endregion

      const containerRef = this.$refs.containerRef;
      const graph = new Graph({
        container: containerRef,
      });
      console.log("UmlJson", UmlJson);
      const cells = [];
      const edgeShapes = [
        "extends",
        "composition",
        "implement",
        "aggregation",
        "association",
      ];
      UmlJson.forEach((item) => {
        if (edgeShapes.includes(item.shape)) {
          cells.push(graph.createEdge(item));
        } else {
          cells.push(graph.createNode(item));
        }
      });
      graph.resetCells(cells);
      graph.zoomToFit({ padding: 10, maxScale: 1 });
    },
  },
};
</script>


<style scoped>
.content {
  font-family: sans-serif;
  display: flex;
}

.app-stencil {
  width: 250px;
  border: 1px solid #f0f0f0;
  position: relative;
}

.app-content {
  flex: 1;
  height: 520px;
  margin-left: 8px;
  margin-right: 8px;
  box-shadow: 0 0 10px 1px #e9e9e9;
}

.x6-graph-scroller {
  border: 1px solid #f0f0f0;
  margin-left: -1px;
}
</style>
